//============================================================================
// Name        : EESTrade-1.cpp
// Author      :
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_TRACE // ���붨�������,��������ļ������к�
#include "spdlog/spdlog.h"
#include "spdlog/spdlog-inl.h"
#include "spdlog/async.h"
#include "spdlog/sinks/daily_file_sink.h"
#include "spdlog/pattern_formatter.h"
#include <iostream>
#include <set>
#include "src/strategy/BaseStrategy.h"
#include "src/CNanoNetAdapter.cpp"
#include "src/ActualEESTraderApi.h"
#include "crow.h"
using namespace std;

int main()
{

    spdlog::init_thread_pool(8192, 1);

    std::shared_ptr<spdlog::logger> p_logger = spdlog::daily_logger_mt<spdlog::async_factory>("log", "logs/day");

    spdlog::set_default_logger(p_logger);

    spdlog::set_pattern(*p_logger, "[%Y-%m-%d %H:%M:%S.%e][thread %t][%@,%!][%l]:%v");

    p_logger->set_level(spdlog::level::debug);
    spdlog::default_logger()->flush_on(spdlog::level::err);
    map<string, string> accountParamsMap;

    map<string, string> strategyMap;
    {
        RedisImp redis("127.0.0.1");
        redis.getRedis().hgetall("accountParams", std::inserter(accountParamsMap, accountParamsMap.begin()));
        redis.getRedis().hgetall("strategy", std::inserter(strategyMap, strategyMap.begin()));
    }

    auto p_engine = DataEngine::getInstancePtr();
    p_engine->loadContracts();
    auto p_api = make_unique<ActualEESTraderApi>(accountParamsMap, p_engine);

    sleep(1);

    p_engine->loadCancelMap();

    for (auto &it : strategyMap)
    {
        if (!it.first.empty())
        {
            string s = it.first;
            vector<string> v;
            utils::SplitString(s, v, "|");
            string clazz = v[0];
            string params = v[1];
            if (strcmp(clazz.c_str(), "BigOrderTrader_3") == 0)
            {

                // std::shared_ptr<BaseStrategy> p_strategy=std::make_shared<BigOrderTrader_3>(index++, p_engine.get(), it.second);
//                BaseStrategy *p_strategy = new BigOrderTrader_3();
//                p_strategy->initStrategy(p_engine, it.second);
            }
        }
    }

    auto p_adapter = make_unique<CNanoNetAdapter>(p_engine);
    p_adapter->startRecv();

    p_api->m_tradeApi->QuerySymbolStatus();
    sleep(1);
    p_api->startUdpOrderThread();
    sleep(1);
    p_engine->initEngine();
    p_engine->startEngine();
    p_engine->startAllStrategy();
    crow::SimpleApp app;
    crow::mustache::set_base(".");
    crow::mustache::set_global_base("templates");
    crow::logger::setLogLevel(crow::LogLevel::ERROR);
    CROW_ROUTE(app, "/")
    ([p_engine]()
     {
        crow::mustache::context ctx;
        vector<crow::json::rvalue> res;
        for (auto item: p_engine->strategies) {
            json tmpJson = item.second->getAllParams();
            tmpJson["mdTimes"] = item.second->mdTimes;
            tmpJson["isActive"] = item.second->isActive;
            tmpJson["position"] = item.second->getPositions();
            string tmp = tmpJson.dump();
            res.push_back(crow::json::load(tmp.c_str()));
        }
        vector<crow::json::rvalue> allInformation;
        for (const auto &item: p_engine->informationMap) {
            json j = nlohmann::json{
                    {"contractCode", item.first},
                    {"information",  item.second.load(std::memory_order_relaxed)}
            };
            allInformation.push_back(crow::json::load(j.dump()));
        }

        ctx["strategies"] = res;
        ctx["lastOffset"] = p_engine->lastOffset;
        ctx["traderTime"] = p_engine->traderTime;
        ctx["allInformation"] = allInformation;
        ctx["maxToken"] = p_engine->getCurrentToken();
        ctx["InitialBp"]=p_engine->InitialBp;
        return crow::mustache::load("index.html").render(ctx); });

    CROW_ROUTE(app, "/show/<string>")
    ([p_engine](const string &className)
     {
        crow::mustache::context ctx;
        vector<crow::json::rvalue> res;
        for (auto item: p_engine->strategies) {
            if (item.second->getClassName() == className) {
                json tmpJson = item.second->getAllParams();
                tmpJson["mdTimes"] = item.second->mdTimes;
                tmpJson["isActive"] = item.second->isActive;
                tmpJson["position"] = item.second->getPositions();
                string tmp = tmpJson.dump();
                res.push_back(crow::json::load(tmp.c_str()));
            }
        }
        ctx["strategies"] = res;
        ctx["lastOffset"] = p_engine->lastOffset;
        ctx["traderTime"] = p_engine->traderTime;
        ctx["InitialBp"]=p_engine->InitialBp;
        string fileName = className + ".html";
        return crow::mustache::load(fileName).render(ctx); });

    CROW_ROUTE(app, "/showFinRate")
            ([]()
             {
                 crow::mustache::context ctx;
                 RedisImp redisImp("127.0.0.1");
                 auto res=redisImp.getRedis().lindex("finance_rate", 0);
                 if(res.has_value())
                 {
                     ctx["financeRate"]=crow::json::load(res.value());
                 }
                 return crow::mustache::load("finance.html").render(ctx); });

    CROW_ROUTE(app, "/add_strategy").methods("POST"_method)
            ([p_engine](const crow::request &req) {
                try {
                    vector<string> contractCodes;
                    json params = json::parse(req.body);
                    if (params.contains("clazz")) {
                        string clazz = params.at("clazz").get<string>();
                        if (strcmp(clazz.c_str(), "CashTrader_1") == 0) {
                            string contractCode = params.at("contractCode").get<string>();
                            if (p_engine->contractMap.find(contractCode) != p_engine->contractMap.end()) {
                 /*               contractCodes.push_back(contractCode);
                                params["contractCodes"] = contractCodes;
                                params.erase("contractCode");
                                auto p_strategy = new CashTrader_1();
                                p_strategy->initStrategy(p_engine, params.dump());
                                p_engine->initEngine();*/
                            }
                        }
                    }

                    crow::response res;
                    return res;
                }
                catch (const std::exception &e) {
                    std::cerr << "Error: " << e.what() << std::endl;
                    crow::response res;
                    res.code = 400;
                    res.end(e.what());
                    return res;
                }
            });
    CROW_ROUTE(app, "/del_strategy").methods("POST"_method)([p_engine](const crow::request &req)
                                                            {
                try {
                    json params = json::parse(req.body);
                    int strategyId = params.at("strategyId").get<int>();
                    auto it = p_engine->strategies.find(strategyId);
                    if (it != p_engine->strategies.end()) {
                        p_engine->delStrategy(it->second);
                    }
                    crow::response res;
                    return res;
                }
                catch (const std::exception &e) {
                    std::cerr << "Error: " << e.what() << std::endl;
                    crow::response res;
                    res.code = 400;
                    res.end(e.what());
                    return res;
                } });
    CROW_ROUTE(app, "/start_strategy").methods("POST"_method)([p_engine](const crow::request &req)
                                                              {
                try {
                    json params = json::parse(req.body);
                    int strategyId = params.at("strategyId").get<int>();
                    auto it = p_engine->strategies.find(strategyId);
                    if (it != p_engine->strategies.end()) {
                        if(it->second->isActive)
                        {
                            it->second->stop();
                        }
                        else {
                            it->second->start();
                        }
                    }
                    crow::response res;
                    return res;
                }
                catch (const std::exception &e) {
                    std::cerr << "Error: " << e.what() << std::endl;
                    crow::response res;
                    res.code = 400;
                    res.end(e.what());
                    return res;
                } });

    CROW_ROUTE(app, "/modify_strategy").methods("POST"_method)([p_engine](const crow::request &req)
                                                               {
                try {
                    json params = json::parse(req.body);
                    int strategyId = params.at("strategyId").get<int>();
                    auto it = p_engine->strategies.find(strategyId);
                    if (it != p_engine->strategies.end()) {
                        it->second->upJsonParams();
                        it->second->jsonParams.merge_patch(params);
                        it->second->loadParams(it->second->jsonParams.dump());
                    }
                    crow::response res(302);
                    return res;
                }
                catch (const std::exception &e) {
                    std::cerr << "Error: " << e.what() << std::endl;
                    crow::response res;
                    res.code = 400;
                    res.end(e.what());
                    return res;
                } });

    CROW_ROUTE(app, "/operateAll").methods("POST"_method)([p_engine](const crow::request &req)
                                                          {
                try {
                    json params = json::parse(req.body);
                    int select = params.at("select").get<int>();

                    if(select == 1)
                    {
                        p_engine->startAllStrategy();
                    }
                    else if(select == 2)
                    {
                        p_engine->stopAllStrategy();
                    }
                    else if(select==3)
                    {
                    for (const auto &item: p_engine->strategies) {
                    item.second->saveParams();
                    }
                    }
                    else if(select==-1)
                    {
                    p_engine->saveCancelMap();
                    p_engine->stopAllStrategy();
                    exit(0);
                    }
                                 
                    crow::response res(302);
                    return res;
                }
                catch (const std::exception &e) {
                    std::cerr << "Error: " << e.what() << std::endl;
                    crow::response res;
                    res.code = 400;
                    res.end(e.what());
                    return res;
                } });

    app.port(9201).run();
}
